import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;

public class MyThreadPool {

    List<Thread> threads = new ArrayList<>();

//    //1.线程什么时候创建
//    //2线程的runnable是什么？是我们提交command吗？
//    void execute(Runnable commend){
//        Thread thread = new Thread(commend);
//        threads.add(thread);
//        thread.start();
//    }

    //一个线程复用
//    List<Runnable> commandList = new ArrayList<>();
//
//    Thread thread = new Thread(() -> {
//        //这有一个问题
//        //如果commandList为空，这一块他会无谓的消耗cpu资源
//        //那么我们就需要一种容器，当commandList为空的时候，阻塞在这里，让他不消耗cpu资源 -- 阻塞队列
//        while(true){
//            if(!commandList.isEmpty()){
//                Runnable command = commandList.remove(0);
//                command.run();
//            }
//        }
//    });
//
//    void execute(Runnable command){
//        commandList.add(command);
//    }


//    ArrayBlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<>(1024);
//    Thread thread = new Thread(() -> {
//        while(true){
//            try {
//                Runnable command = blockingQueue.take();
//                command.run();
//            } catch (InterruptedException e) {
//                throw new RuntimeException(e);
//            }
//        }
//    },"唯一线程");
//
//    {
//        thread.start();
//    }
//
//    void execute(Runnable command){
//        boolean offer = blockingQueue.offer(command);
//    }

//    ArrayBlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<>(1024);
//
//    //task 是为了未来我们创建的所有线程都执行这段逻辑而启动的
//    private final  Runnable task = () -> {
//        while(true){
//            try {
//                Runnable command = blockingQueue.take();
//                command.run();
//            } catch (InterruptedException e) {
//                throw new RuntimeException(e);
//            }
//        }
//    };
//
//   private int corePoolSize = 10;
//   private int maxSize = 15;
//
//    //我们的线程池 应该有多少个线程
//    List<Thread> coreList = new ArrayList<>();
//
//    List<Thread> supportList = new ArrayList<>();
//
//    //我们判断 threadList 中有多少个元素 如果没有到 corePoolSize 那么我们就创建线程
//    void execute(Runnable command){
//        if(coreList.size() < corePoolSize){
//            Thread thread = new Thread(task);
//            coreList.add(thread);
//            thread.start();
//        }
//        if (blockingQueue.offer(command)) {
//            return;
//        }
//        if(coreList.size() + supportList.size() < maxSize){
//            Thread thread = new Thread(task);
//            supportList.add(thread);
//            thread.start();
//        }
//        if(!blockingQueue.offer(command)){
//            throw new RuntimeException("阻塞队列满了！")
//        }
//    }


//    //思考一个线程如何让自己在空闲的时候结束呢？
//     //如果我们在阻塞的过程中，设置一个超时时间，超过这个时间，我们任然没有从阻塞队列里拿出任务 ，我们就认为此时这个线程池是一个不忙碌的状态，
//    //那么应该结束的这些辅助线程，就应该自己结束 。
//    //而 BlockingQueue 又一个 poll 函数可以满足我们的需求，我们只需让非核心线程使用 poll 函数从队列里取元素即可
//    ArrayBlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<>(1024);
//
//    //task 是为了未来我们创建的所有线程都执行这段逻辑而启动的
//    private final  Runnable coreTask = () -> {
//        while(true){
//            try {
//                Runnable command = blockingQueue.take();
//                command.run();
//            } catch (InterruptedException e) {
//                throw new RuntimeException(e);
//            }
//        }
//    };
//
//    private final  Runnable supportTask = () -> {
//        while(true){
//            try {
//                //现在就有有一个问题了，我们的 超时时间 应该设置为多少？ -- 放到构造函数里面，让使用者自己指定
//                Runnable command = blockingQueue.poll(1, TimeUnit.SECONDS);
//                if(command == null){
//                    break;
//                }
//                command.run();
//            } catch (InterruptedException e) {
//                throw new RuntimeException(e);
//            }
//        }
//
//        System.out.println(Thread.currentThread().getName() + "线程结束啦！");
//    };
//
//    private int corePoolSize = 10;
//    private int maxSize = 15;
//
//    //我们的线程池 应该有多少个线程
//    List<Thread> coreList = new ArrayList<>();
//
//    List<Thread> supportList = new ArrayList<>();
//
//    //我们判断 threadList 中有多少个元素 如果没有到 corePoolSize 那么我们就创建线程
//    void execute(Runnable command){
//        if(coreList.size() < corePoolSize){
//            Thread thread = new Thread(coreTask);
//            coreList.add(thread);
//            thread.start();
//        }
//        if (blockingQueue.offer(command)) {
//            return;
//        }
//        if(coreList.size() + supportList.size() < maxSize){
//            Thread thread = new Thread(supportTask);
//            supportList.add(thread);
//            thread.start();
//        }
//        if(!blockingQueue.offer(command)){
//            throw new RuntimeException("阻塞队列满了！");
//        }
//    }


//    //思考一个线程如何让自己在空闲的时候结束呢？
//    //如果我们在阻塞的过程中，设置一个超时时间，超过这个时间，我们任然没有从阻塞队列里拿出任务 ，我们就认为此时这个线程池是一个不忙碌的状态，
//    //那么应该结束的这些辅助线程，就应该自己结束 。
//    //而 BlockingQueue 又一个 poll 函数可以满足我们的需求，我们只需让非核心线程使用 poll 函数从队列里取元素即可
//    ArrayBlockingQueue<Runnable> blockingQueue;
//
//    private int corePoolSize;
//    private int maxSize;
//    private int timeout;
//    private TimeUnit timeUnit;
//
//    public MyThreadPool(int corePoolSize, int maxSize, int timeout, TimeUnit timeUnit, BlockingQueue<Runnable> blockingQueue) {
//        this.corePoolSize = corePoolSize;
//        this.maxSize = maxSize;
//        this.timeout = timeout;
//        this.timeUnit = timeUnit;
//        this.blockingQueue = (ArrayBlockingQueue<Runnable>) blockingQueue;
//    }
//
//    //task 是为了未来我们创建的所有线程都执行这段逻辑而启动的
////    private final  Runnable coreTask = () -> {
////
////    };
//
////    private final  Runnable supportTask = () -> {
////
////    };
//
//    //我们的线程池 应该有多少个线程
//    List<Thread> coreList = new ArrayList<>();
//
//    List<Thread> supportList = new ArrayList<>();
//
//    //我们判断 threadList 中有多少个元素 如果没有到 corePoolSize 那么我们就创建线程
//    void execute(Runnable command){
//        if(coreList.size() < corePoolSize){
//            Thread thread = new CoreThread();
//            coreList.add(thread);
//            thread.start();
//        }
//        if (blockingQueue.offer(command)) {
//            return;
//        }
//        if(coreList.size() + supportList.size() < maxSize){
//            Thread thread = new SupportThread();
//            supportList.add(thread);
//            thread.start();
//        }
//        if(!blockingQueue.offer(command)){
//            throw new RuntimeException("阻塞队列满了！");
//        }
//    }
//
//    class CoreThread extends Thread{
//        @Override
//        public void run() {
//            while(true){
//                try {
//                    Runnable command = blockingQueue.take();
//                    command.run();
//                } catch (InterruptedException e) {
//                    throw new RuntimeException(e);
//                }
//            }
//        }
//    }
//
//    class SupportThread extends Thread{
//        @Override
//        public void run() {
//            while(true){
//                try {
//                    //现在就有有一个问题了，我们的 超时时间 应该设置为多少？ -- 放到构造函数里面，让使用者自己指定
//                    Runnable command = blockingQueue.poll(timeout,timeUnit);
//                    if(command == null){
//                        break;
//                    }
//                    command.run();
//                } catch (InterruptedException e) {
//                    throw new RuntimeException(e);
//                }
//            }
//
//            System.out.println(Thread.currentThread().getName() + "线程结束啦！");
//        }
//    }

//思考一个线程如何让自己在空闲的时候结束呢？
//如果我们在阻塞的过程中，设置一个超时时间，超过这个时间，我们任然没有从阻塞队列里拿出任务 ，我们就认为此时这个线程池是一个不忙碌的状态，
//那么应该结束的这些辅助线程，就应该自己结束 。
//而 BlockingQueue 又一个 poll 函数可以满足我们的需求，我们只需让非核心线程使用 poll 函数从队列里取元素即可
    public ArrayBlockingQueue<Runnable> blockingQueue;
    private int corePoolSize;
    private int maxSize;
    private int timeout;
    private TimeUnit timeUnit;
    private RejectHandler rejectHandler;

    public MyThreadPool(int corePoolSize, int maxSize, int timeout, TimeUnit timeUnit, BlockingQueue<Runnable> blockingQueue,RejectHandler rejectHandler) {
        this.corePoolSize = corePoolSize;
        this.maxSize = maxSize;
        this.timeout = timeout;
        this.timeUnit = timeUnit;
        this.blockingQueue = (ArrayBlockingQueue<Runnable>) blockingQueue;
        this.rejectHandler = rejectHandler;
    }

    //task 是为了未来我们创建的所有线程都执行这段逻辑而启动的
//    private final  Runnable coreTask = () -> {
//
//    };

//    private final  Runnable supportTask = () -> {
//
//    };

    //我们的线程池 应该有多少个线程
    List<Thread> coreList = new ArrayList<>();

    List<Thread> supportList = new ArrayList<>();

    //我们判断 threadList 中有多少个元素 如果没有到 corePoolSize 那么我们就创建线程
    void execute(Runnable command){
        if(coreList.size() < corePoolSize){
            Thread thread = new CoreThread();
            coreList.add(thread);
            thread.start();
        }
        if (blockingQueue.offer(command)) {
            return;
        }
        if(coreList.size() + supportList.size() < maxSize){
            Thread thread = new SupportThread();
            supportList.add(thread);
            thread.start();
        }
        if(!blockingQueue.offer(command)){
            //在这里阻塞队列满了的情况下，我们只能选择抛异常嘛？？
            //此时就有了 拒绝策略登场了
//            throw new RuntimeException("阻塞队列满了！");
            rejectHandler.regject(command,this);
        }
    }

    class CoreThread extends Thread{
        @Override
        public void run() {
            while(true){
                try {
                    Runnable command = blockingQueue.take();
                    command.run();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    class SupportThread extends Thread{
        @Override
        public void run() {
            while(true){
                try {
                    //现在就有有一个问题了，我们的 超时时间 应该设置为多少？ -- 放到构造函数里面，让使用者自己指定
                    Runnable command = blockingQueue.poll(timeout,timeUnit);
                    if(command == null){
                        break;
                    }
                    command.run();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }

            System.out.println(Thread.currentThread().getName() + "线程结束啦！");
        }
    }
}
